using CfgTable;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class LevelPlayDisplayObjCtrl : LevelPlaySubBaseCtrl
    {
        /// <summary>
        /// 带trigger区域的实体 BVH查询树，aabb来查询
        /// </summary>
        private BVHTree2D<SceneDisplayObject> _triggerBVHTree;
        private bool _activeUpdate;
        private Dictionary<int, SceneDisplayObject> _objects = new Dictionary<int, SceneDisplayObject>();
        private float _checkTime;

        private HashSet<SceneDisplayObject> _curObjInRange = new HashSet<SceneDisplayObject>();
        private HashSet<SceneDisplayObject> _objNoLongerInRange = new HashSet<SceneDisplayObject>();

        protected override void OnModuleGameplayInit()
        {
            this.regionCtrl.sceneCtrl.AddPreloadAfterScene(Preload);
        }

        private UniTask Preload()
        {
            _triggerBVHTree = new BVHTree2D<SceneDisplayObject>(BVHBounds2D.FromRect(regionCtrl.navigationCtrl.boundsRect));
            return UniTask.CompletedTask;
        }

        protected override void OnSceneLoaded()
        {
            _activeUpdate = true;
        }

        public void OnSceneBlockChanged(bool isToRemoved, GameObject blockGameObject)
        {
            if (blockGameObject == null)
                return;
            ViewObjTriggerActionComponent[] components = blockGameObject.GetComponentsInChildren<ViewObjTriggerActionComponent>(true);
            if (components.Length > 0)
            {
                if (!isToRemoved)
                {
                    foreach (ViewObjTriggerActionComponent component in components)
                    {
                        AddObject(component.gameObject, component.triggerRange, component.actionType, component.restoreOnFarAway);
                    }
                }
                else
                {
                    foreach (ViewObjTriggerActionComponent component in components)
                    {
                        RemoveObject(component.gameObject);
                    }
                }
            }
        }

        private void AddObject(GameObject gameObject, Bounds triggerRange, SceneObjectTriggerActionType actionType, bool restoreOnFarAway)
        {
            SceneDisplayObject obj = ClassPool.Get<SceneDisplayObject>();
            bool isSuccess = obj.Init(gameObject, triggerRange, actionType, restoreOnFarAway);
            if (!isSuccess)
            {
                return;
            }
            _objects.Add(gameObject.GetInstanceID(), obj);

            InsertIntoBvhTree(obj);
        }

        private void RemoveObject(GameObject gameObject)
        {
            int insId = gameObject.GetInstanceID();
            if (_objects.TryGetValue(insId, out var obj))
            {
                _objects.Remove(insId);
                RemoveFromBvhTree(obj);
                ClassPool.Put(obj);
            }
        }

        public void OnAddEntity(LevelPlayRealityEntity entity)
        {
            if (entity == null)
                return;
            if (entity.cfgEntity == null || entity.cfgEntity.ViewTriggerAction == 0)
                return;
            CfgLevelEntityViewTriggerAction cfTriggerAction = TableCenter.levelEntityViewTriggerAction.Get(entity.cfgEntity.ViewTriggerAction);
            Vector3 boxCenter = cfTriggerAction.BoxCenter.ToVector3(GameGlobalConst.LogicPosScale);
            Vector3 boxSize = cfTriggerAction.BoxSize.ToVector3(GameGlobalConst.LogicPosScale);
            AddObject(entity.gameObject, new Bounds(boxCenter, boxSize), cfTriggerAction.ActionType, cfTriggerAction.RestoreOnFarAway);
        }

        public void OnRemoveEntity(LevelPlayRealityEntity entity)
        {
            if (entity == null)
                return;
            if (entity.cfgEntity == null || entity.cfgEntity.ViewTriggerAction == 0)
                return;
            RemoveObject(entity.gameObject);
        }

        public void UpdateEntity(LevelPlayRealityEntity entity)
        {
            if (entity == null)
                return;
            if (entity.cfgEntity == null || entity.cfgEntity.ViewTriggerAction == 0)
                return;
            if (_objects.TryGetValue(entity.gameObject.GetInstanceID(), out var obj))
            {
                UpdateBvhTree(obj);
            }
        }

        public static BVHBounds2D GetBVHBounds(SceneDisplayObject obj)
        {
            var pos = obj.gameObject.transform.position + obj.triggerRange.center;

            Vector2 posV2 = new Vector2(pos.x, pos.z);
            Vector2 sizeV2 = new Vector2(obj.triggerRange.size.x, obj.triggerRange.size.z);

            if (obj.isTriggerRotate)
            {
                return BVHBounds2D.FromPosSizeRotationY(posV2, sizeV2, obj.gameObject.transform.rotation.eulerAngles.y);
            }

            return BVHBounds2D.FromPosSize(posV2, sizeV2);
        }

        private void InsertIntoBvhTree(SceneDisplayObject obj)
        {
            obj.bvhBounds = GetBVHBounds(obj);
            _triggerBVHTree.Insert(obj);
        }

        private void UpdateBvhTree(SceneDisplayObject obj)
        {
            _triggerBVHTree.Update(obj, GetBVHBounds(obj));
        }

        private void RemoveFromBvhTree(SceneDisplayObject obj)
        {
            _triggerBVHTree.Remove(obj);
        }

        protected override void OnUpdate(float deltaTime)
        {
            if (!_activeUpdate)
                return;
            _checkTime += deltaTime;
            if (_checkTime >= GameGlobalConst.EntityLogicInterval)
            {
                _checkTime = 0;
                CheckLogic();
            }
        }

        private void CheckLogic()
        {
            var character = regionCtrl.entityCtrl.GetMainCharacter();
            if (character == null)
            {
                return;
            }

            var characerUnityPos = character.GetUnityVec3Pos();
            List<SceneDisplayObject> bvhEntitys = ListPool<SceneDisplayObject>.Get();
            if (_objects.Count > 0)
            {
                // 查询bvhtree 
                var characterBounds = BVHBounds2D.FromPosSize(characerUnityPos, LevelPlayEntityCtrl.CharacterObbSize);
                _triggerBVHTree.RetrieveObjects(bvhEntitys, characterBounds);
            }

            foreach (var item in _curObjInRange)
            {
                _objNoLongerInRange.Add(item);
            }

            if (bvhEntitys.Count > 0)
            {
                //创建主角OBB
                var characterOBB = new OBBRect(characerUnityPos, LevelPlayEntityCtrl.CharacterObbSize, 0);
                foreach (SceneDisplayObject sceneObj in bvhEntitys)
                {
                    if (!sceneObj.IsInHeightRange(characerUnityPos.y))
                    {
                        continue;
                    }

                    var offset = sceneObj.isTriggerRotate ? sceneObj.gameObject.transform.rotation * sceneObj.triggerRange.center : sceneObj.triggerRange.center;
                    float rotationY = sceneObj.isTriggerRotate ? sceneObj.gameObject.transform.rotation.eulerAngles.y : 0;
                    var entityOBB = new OBBRect(sceneObj.position + offset, sceneObj.triggerRange.size, rotationY);
                    //碰撞
                    if (characterOBB.IsIntersecting(entityOBB))
                    {
                        if (_objNoLongerInRange.Count > 0)
                        {
                            _objNoLongerInRange.Remove(sceneObj);
                        }
                        //仅需要还原的对象才放入当前范围内的对象，当前范围内的对象的作用就是还原
                        if (sceneObj.DoAction())
                        {
                            if (sceneObj.restoreOnFarAway)
                            {
                                _curObjInRange.Add(sceneObj);
                            }
                            //不需要还原的直接移除，因为它不再会有任何被程序操控的表现
                            else
                            {
                                RemoveObject(sceneObj.gameObject);
                            }
                        }
                    }
                }
            }

            foreach (SceneDisplayObject revertObj in _objNoLongerInRange)
            {
                revertObj.DoRevertAction();
                _curObjInRange.Remove(revertObj);
            }
            _objNoLongerInRange.Clear();

            ListPool<SceneDisplayObject>.Put(bvhEntitys);
        }

        protected override void OnDispose()
        {
            _triggerBVHTree?.Clear();
            foreach (var kv in _objects)
            {
                ClassPool.Put(kv.Value);
            }
            _objects.Clear();
        }
    }
}
